﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Xml.Serialization;
using GalaSoft.MvvmLight;

namespace AutoCorrelatorGUI.Model
{
   [SettingsSerializeAs(SettingsSerializeAs.Xml)]
   public class StatsColumnItem : ObservableObject
   {
      bool _SettingChildren = false;
      bool? _IsChecked = false;
      private DataGridColumn _Column = null;

      public StatsColumnItem()
      {
         Header = "";
         Children = new BindingList<StatsColumnItem>();

         Binding = "";
         Format = "";
         Expanded = false;
         ToolTip = "";
      }

      public StatsColumnItem(string header, string binding, string format, string tooltip = "")
      {
         this.Header = header;
         this.Children = new BindingList<StatsColumnItem>();

         Binding = binding;
         Format = format;
         Expanded = false;

         if (String.IsNullOrWhiteSpace(tooltip))
            ToolTip = header;
         else
            ToolTip = tooltip;
      }

      public event EventHandler CheckedChanged;

      /// <summary>
      /// Gets/sets the state of the associated UI toggle (ex. CheckBox).
      /// The return value is calculated based on the check state of all
      /// child FooViewModels.  Setting this property to true or false
      /// will set all children to the same check state, and setting it 
      /// to any value will cause the parent to verify its check state.
      /// </summary>
      public bool? IsChecked
      {
         get { return _IsChecked; }
         set { this.SetIsChecked(value); }
      }

      [XmlIgnore()]
      public bool IsInitiallySelected { get; private set; }

      [XmlAttribute()]
      public string Header { get; set; }

      [XmlAttribute()]
      public string Binding { get; set; }

      [XmlAttribute()]
      public string Format { get; set; }

      public string ToolTip { get; set; }

      /// <summary>
      /// The <see cref="Expanded" /> property's name.
      /// </summary>
      public const string IsExpandedPropertyName = "Expanded";

      private bool _Expanded = false;

      /// <summary>
      /// Sets and gets the Expanded property.
      /// Changes to that property's value raise the PropertyChanged event. 
      /// </summary>
      [XmlAttribute()]
      public bool Expanded
      {
         get
         {
            return _Expanded;
         }
         set
         {
            if (_Expanded == value)
            {
               return;
            }

            _Expanded = value;
            RaisePropertyChanged(IsExpandedPropertyName);
         }
      }

      private BindingList<StatsColumnItem> _Children = null;

      public BindingList<StatsColumnItem> Children
      {
         get
         {
            return _Children;
         }
         set
         {
            //Need to move the event handlers
            if (_Children != null)
            {
               _Children.ListChanged -= Children_ListChanged;
            }

            _Children = value;

            if (_Children != null)
            {
               _Children.ListChanged += Children_ListChanged;
            }
         }
      }

      private void OnCheckChanged()
      {
         if (CheckedChanged != null)
         {
            CheckedChanged(this, new EventArgs());
         }
      }

      void Children_ListChanged(object sender, ListChangedEventArgs e)
      {
         if (e.ListChangedType == ListChangedType.ItemAdded)
         {
            ((sender as BindingList<StatsColumnItem>)[e.NewIndex] as StatsColumnItem).CheckedChanged += Item_CheckedChanged;
         }
      }

      void Item_CheckedChanged(object sender, EventArgs e)
      {
         if (!_SettingChildren)
         {
            //Update our check changed 
            bool? state = null;
            for (int i = 0; i < this.Children.Count; ++i)
            {
               bool? current = this.Children[i].IsChecked;
               if (i == 0)
               {
                  state = current;
               }
               else if (state != current)
               {
                  state = null;
                  break;
               }
            }

            bool didChange = _IsChecked != state;

            _IsChecked = state;

            if (didChange)
            {
               RaisePropertyChanged("IsChecked");
            }
         }

         //Forward the child event
         if (CheckedChanged != null)
         {
            CheckedChanged(sender, e);
         }
      }

      public DataGridColumn GetColumn()
      {
         if (_Column == null && !String.IsNullOrWhiteSpace(Binding))
         {
            _Column = new DataGridTextColumn() { Header = Header, Binding = new Binding(Binding) { StringFormat = Format }, CanUserSort = false, MaxWidth = 100 };

            if (!String.IsNullOrWhiteSpace(ToolTip))
            {
               Style cellStyle = new Style(typeof(DataGridCell));
               cellStyle.Setters.Add(new Setter(DataGridCell.ToolTipProperty, ToolTip));

               _Column.CellStyle = cellStyle;

               Style headerStyle = new Style(typeof(DataGridColumnHeader));
               cellStyle.Setters.Add(new Setter(DataGridColumnHeader.ToolTipProperty, ToolTip));
               _Column.HeaderStyle = headerStyle;
            }
         }

         return _Column;
      }

      public List<DataGridColumn> GetAllChildColumns()
      {
         var desc = new List<DataGridColumn>();
         if (IsChecked.GetValueOrDefault(false) && !String.IsNullOrWhiteSpace(Binding))
         {
            desc.Add(GetColumn());
         }

         foreach (var child in Children)
         {
            desc.AddRange(child.GetAllChildColumns());
         }

         return desc;
      }

      void SetIsChecked(bool? value)
      {
         if (value == _IsChecked)
            return;

         _IsChecked = value;

         _SettingChildren = true;

         if (_IsChecked.HasValue)
         {
            foreach (var child in Children)
            {
               child.SetIsChecked(_IsChecked);
            }
         }

         //Throw a check changed event to get the parents to update
         OnCheckChanged();

         _SettingChildren = false;

         RaisePropertyChanged("IsChecked");
      }
   }
}
